package com.wing.productionPlan.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wing.common.enums.MaintenanceEnum;
import com.wing.common.exception.BusinessException;
import com.wing.common.utils.CodeUtil;
import com.wing.common.utils.UniqueIdGeneratorUtil;
import com.wing.config.BaseDataInit;
import com.wing.enterprise.feign.EnterpriseClient;
import com.wing.enterprise.product.model.response.OrderSkuDetailSearchVo;
import com.wing.productionPlan.dao.DynamicDao;
import com.wing.productionPlan.dao.ProductionPlanDao;
import com.wing.productionPlan.model.entity.*;
import com.wing.productionPlan.model.request.*;
import com.wing.productionPlan.model.response.ProductionPlanVO;
import com.wing.productionPlan.model.response.ProductionWorkOrderVO;
import com.wing.web.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 生产计划-ServiceImpl
 *
 * @author
 */
@Service
@Slf4j
public class ProductionPlanServiceImpl extends ServiceImpl<ProductionPlanDao, ProductionPlan> implements ProductionPlanService {
    @Autowired
    private EnterpriseClient enterpriseClient;
    @Autowired
    private ProductionProcessDeviceService productionProcessDeviceService;
    @Autowired
    private ProductionProcessMaterialService productionProcessMaterialService;
    @Autowired
    private ProductionWorkOrderService productionWorkOrderService;
    @Autowired
    private ProductionProcessService productionProcessService;
    @Autowired
    private DynamicDao dynamicDao;
    @Autowired
    private AuditRecordService auditRecordService;

    @Autowired
    private ProductionPlanService productionPlanService;


    @Autowired
    private ProductionPlanRecordService productionPlanRecordService;



    @Override
    public List<ProductionPlanVO> list4app(Map<String, Object> params) {
        return baseMapper.list4app(params);
    }

    @Override
    public Page<ProductionPlanVO> pageList4app(Page page, Map<String, Object> params) {
        List<ProductionPlanVO> list = baseMapper.list4app(page, params);
        page.setRecords(list);
        return page;
    }

    @Override
    public ProductionPlanVO get4appById(Long id) {
        return baseMapper.get4appById(id);
    }

    @Transactional
    @Override
    public void submitProductionPlan(SubmitProductionPlanOutForm submitProductionPlanOutForm) {
        if (CollectionUtils.isEmpty(submitProductionPlanOutForm.getSubmitProductionPlanForms())) {
            throw new BusinessException("参数异常");
        }
        ProductionPlan productionPlan = baseMapper.selectById(submitProductionPlanOutForm.getProductionPlanId());
        if (productionPlan == null) {
            throw new BusinessException("生产计划不存在");
        }
        String enterpriseCode = BaseDataInit.ENTERPRISE_DATA.getCode();
        //添加排产记录
        ProductionPlanRecord productionPlanRecord = new ProductionPlanRecord();
        productionPlanRecord.setCode("PC" + DateUtil.format(new Date(), DatePattern.PURE_DATETIME_FORMAT));
        productionPlanRecord.setProductionPlanId(productionPlan.getId());
        productionPlanRecord.setEnterpriseCode(enterpriseCode);
        productionPlanRecord.setProductTime(submitProductionPlanOutForm.getProductTime());
        productionPlanRecord.setProductionPlanId(submitProductionPlanOutForm.getProductionPlanId());
        productionPlanRecord.setProductionPlanQuantity(submitProductionPlanOutForm.getProductionPlanQuantity());
        productionPlanRecord.setProductionPlanHaveQuantity(submitProductionPlanOutForm.getProductionPlanHaveQuantity());
        productionPlanRecord.setStatus(MaintenanceEnum.planRecordStatus.PCZ.getCode());
        productionPlanRecordService.save(productionPlanRecord);

        int sorted = 1;
        for (SubmitProductionPlanForm item : submitProductionPlanOutForm.getSubmitProductionPlanForms()) {
            //生产计划-生产工序
            ProductionProcess process = new ProductionProcess();
            process.setEnterpriseCode(enterpriseCode);
            process.setProcessId(item.getProcessId());
            process.setProcessName(item.getProcessName());
            process.setProductionPlanId(submitProductionPlanOutForm.getProductionPlanId());
            process.setProductionPlanRecordId(productionPlanRecord.getId());
            process.setPieceRateStatus(item.getPieceRateStatus());
            process.setPieceRate(item.getPieceRate());
            if (CollectionUtil.isNotEmpty(item.getDeviceTypeList())){
                String idString = item.getDeviceTypeList().stream()
                        // 提取 id 并转换为字符串
                        .map(info -> String.valueOf(info.getId()))
                        // 用逗号拼接
                        .collect(Collectors.joining(","));
                process.setDeviceTypes(idString);
            }
            productionProcessService.save(process);

            //生成开工单
            ProductionWorkOrder productionWorkOrder = new ProductionWorkOrder();

            SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
            String today = format.format(new Date());
            Integer maxCode = dynamicDao.getDayMaxNo("ord_production_work_order");
            String maxNo = CodeUtil.getCode(maxCode);
            productionWorkOrder.setDay(Integer.valueOf(today));
            productionWorkOrder.setNo(Integer.valueOf(maxNo));
            productionWorkOrder.setEnterpriseCode(enterpriseCode);
            productionWorkOrder.setCode("KGD"+today+maxNo);
            productionWorkOrder.setProcessType(item.getProcessType());
            productionWorkOrder.setProcessId(process.getId());
            productionWorkOrder.setProcessName(process.getProcessName());
            productionWorkOrder.setQualityType(item.getQualityType());
            productionWorkOrder.setProductionPlanId(process.getProductionPlanId());
            productionWorkOrder.setProductionPlanRecordId(productionPlanRecord.getId());
            productionWorkOrder.setSkuCode(submitProductionPlanOutForm.getSkuCode());
            productionWorkOrder.setProductDetailId(submitProductionPlanOutForm.getProductDetailId());
            productionWorkOrder.setOutputQuantity(submitProductionPlanOutForm.getProductionPlanQuantity());
            productionWorkOrder.setProductionQuantity(submitProductionPlanOutForm.getAllProductionPlanQuantity());
            productionWorkOrder.setPredictStartTime(submitProductionPlanOutForm.getPredictStartTime());
            productionWorkOrder.setPredictFinishTime(submitProductionPlanOutForm.getPredictFinishTime());
            //可领用数量 初始化 (换到激活进行初始化)
//            productionWorkOrder.setCanGetQuantity(submitProductionPlanOutForm.getProductionPlanQuantity());
            productionWorkOrder.setBookId(submitProductionPlanOutForm.getBookId());
            productionWorkOrder.setSorted(sorted++);
            productionWorkOrder.setStatus(ProductionWorkOrder.Status.toactivate);
            productionWorkOrder.setWorkOrderQuality(submitProductionPlanOutForm.getWorkOrderQuality());
            productionWorkOrderService.save(productionWorkOrder);

            //生产工序-生产设备
//            for (ProductionProcessDeviceForm device : item.getProcessDeviceList()) {
//                if (item.getProcessId().equals(device.getProcessId())) {
//                    ProductionProcessDevice processDevice = new ProductionProcessDevice();
//                    SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
//                    String today = format.format(new Date());
//                    Integer maxCode = dynamicDao.getDayMaxNo("ord_production_process_device");
//                    String maxNo = CodeUtil.getCode(maxCode);
//                    processDevice.setCode(productionPlanRecord.getCode() + "-" + process.getProcessName() + "-" + maxNo);
//                    processDevice.setNo(Integer.valueOf(maxNo));
//                    processDevice.setDay(Integer.valueOf(today));
//                    processDevice.setEnterpriseCode(enterpriseCode);
//                    processDevice.setDeviceCode(device.getDeviceCode());
//                    processDevice.setOutputQuantity(0);
//                    processDevice.setProcessId(process.getId());
//                    processDevice.setProductionPlanId(submitProductionPlanOutForm.getProductionPlanId());
//                    processDevice.setProductionPlanRecordId(productionPlanRecord.getId());
//                    processDevice.setCreator(JwtUtils.getLoginUserId());
//                    processDevice.setCreatorName(JwtUtils.getLoginNickname());
//                    productionProcessDeviceService.save(processDevice);
//                }
//            }
            //工序-排产物料
            if (CollectionUtils.isNotEmpty(item.getMaterialList())) {
                for (ProductionProcessMaterialForm material : item.getMaterialList()) {
                    ProductionProcessMaterial processMaterial = new ProductionProcessMaterial();
                    processMaterial.setEnterpriseCode(enterpriseCode);
                    processMaterial.setSkuCode(material.getSkuCode());
                    processMaterial.setSkuName(material.getSkuName());
                    processMaterial.setProcessId(process.getId());
                    processMaterial.setProcessName(process.getProcessName());
                    processMaterial.setMaterialSkuCode(material.getSkuCode());
                    processMaterial.setQuantity(material.getQuantity());
                    processMaterial.setPlanRecordId(productionPlanRecord.getId());
                    processMaterial.setProductDetailId(material.getProductDetailId());
                    processMaterial.setCountQuantity(new BigDecimal(submitProductionPlanOutForm.getProductionPlanQuantity()).multiply(material.getQuantity()).setScale(2, RoundingMode.HALF_UP));
                    processMaterial.setPlanId(submitProductionPlanOutForm.getProductionPlanId());
                    productionProcessMaterialService.save(processMaterial);
                }
            }
            productionPlan.setStatus(ProductionPlan.Status.alreadyrowproduce);
            this.updateById(productionPlan);
        }
    }

    @Transactional
    @Override
    public void cancellationPlan(Long id) {
        ProductionPlan productionPlan = baseMapper.selectById(id);
        if (productionPlan == null) {
            throw new BusinessException("生产计划不存在");
        }
        Map map = new HashMap();
        map.put("productionPlanId", productionPlan.getId());
        List<ProductionWorkOrderVO> list = productionWorkOrderService.list4app(map);
        if (CollectionUtils.isNotEmpty(list)) {
            boolean result = list.stream().filter(m -> m.getStatus().getValue() == 1).findAny().isPresent();
            if (result) {
                throw new BusinessException("当前计划有正在生产的开工单，不能作废！");
            }
            for (ProductionWorkOrderVO item : list) {
                ProductionWorkOrder workOrder = productionWorkOrderService.getById(item.getId());
                workOrder.setStatus(ProductionWorkOrder.Status.termination);
                productionWorkOrderService.updateById(workOrder);
            }
        }
        productionPlan.setStatus(ProductionPlan.Status.cancellation);
        this.updateById(productionPlan);

    }

    @Override
    public ProductionPlanVO getProductionPlanDetailById(Long id) {
        ProductionPlanVO detailById = baseMapper.getProductionPlanDetailById(id);
        return detailById;
    }

    @Override
    public ProductionPlanVO getProductionPlanInfoById(Long id) {
        return baseMapper.getProductionPlanInfoById(id);
    }

    @Override
    public void auditPlan(Long id, String remark, AuditRecord.CheckStatus checkStatus) {
        ProductionPlan productionPlan = baseMapper.selectById(id);
        if (productionPlan == null) {
            throw new BusinessException("计划不存在");
        }
        //审核记录
        AuditRecord auditRecord = new AuditRecord();
        auditRecord.setBusinessId(id)
                .setRemark(remark)
                .setCreatorName(JwtUtils.getLoginUsername())
                .setCheckStatus(checkStatus);
        auditRecordService.save(auditRecord);
        //计划状态
        productionPlan.setStatus(ProductionPlan.Status.checked);
        if (checkStatus.getValue() == 0) {
            productionPlan.setCheckStatus(ProductionPlan.CheckStatus.approve);
        } else {
            productionPlan.setCheckStatus(ProductionPlan.CheckStatus.reject);
            productionPlan.setStatus(ProductionPlan.Status.toconfirmed);
        }
        baseMapper.updateById(productionPlan);
    }

    @Override
    public List<String> getOrderProEnclosure(Long proId) {
        return baseMapper.getOrderProEnclosure(proId);
    }

    @Override
    public void stop(Long productionPlanId) {
        //更新排产计划状态
        ProductionPlan productionPlan = this.baseMapper.selectById(productionPlanId);
        productionPlan.setStatus(ProductionPlan.Status.cancellation);
        this.baseMapper.updateById(productionPlan);
        //更新排产计划-工序

        //更新开工单
    }

    /**
     * 查询剩余数
     * @param orderId 订单id
     * @param type 订单类型
     * @param productDetailId 物料id
     * @return
     */
    @Override
    public Map<String, Object> getQuantityBy(Long orderId, String type, Long productDetailId) {
        //量产订单
        if ("order".equals(type)){
            Map<String, Object> map = this.baseMapper.getOrderQuantityBy(orderId,productDetailId);
            return map;
        }else if("finish".equals(type)){
            Map<String, Object> map = this.baseMapper.getFinishQuantityBy(orderId,productDetailId);
            return map;
        }else {
            return null;
        }
    }

    /**
     * 查询成品code
     * @param orderId
     * @return
     */
    @Override
    public String getFinishCodeBy(Long orderId) {
        return baseMapper.getFinishCodeBy(orderId);
    }

    /**
     * 获取成品订单code
     * @param orderId
     * @return
     */
    @Override
    public String getOrderCodeBy(Long orderId) {
        return baseMapper.getOrderCodeBy(orderId);
    }

    /**
     * 批量提交排产计划
     * @param batchProductionPlanAddForm 批量提交排产计划
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int addBatchPlan(BatchProductionPlanAddForm batchProductionPlanAddForm) {
        List<BatchProductionPlans> batchProductionPlansList = batchProductionPlanAddForm.getBatchProductionPlansList();

        if (CollectionUtils.isNotEmpty(batchProductionPlansList)) {
            //1. 添加计划
            List<ProductionPlan> plans = new ArrayList<>();
            for (BatchProductionPlans batchProductionPlan : batchProductionPlansList) {
                String today = DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN);
                String code = UniqueIdGeneratorUtil.generateUniqueId("P", "yyyyMMdd", 1000, 9999);
                ProductionPlan productionPlan = ProductionPlan.builder()
                        .creator(JwtUtils.getLoginUserId())
                        .day(Integer.valueOf(today))
                        .creatorName(JwtUtils.getLoginUsername())
                        .phone(JwtUtils.getPhone())
                        .code(code)
                        .enterpriseCode(JwtUtils.getEnterpriseCode())
                        .productTypeId(batchProductionPlanAddForm.getProductTypeId())
                        .productTypeName(batchProductionPlanAddForm.getProductTypeName())
                        .customerSkuCode(batchProductionPlan.getCustomerSkuCode())
                        .customerSkuSpec(batchProductionPlan.getCustomerSkuSpec())
                        .customerSkuName(batchProductionPlan.getCustomerSkuName())
                        .accessory(batchProductionPlan.getAccessory())
                        .unitId(batchProductionPlan.getUnitId())
                        .unitName(batchProductionPlan.getUnitName())
                        .orderType(batchProductionPlanAddForm.getOrderType())
                        .productionQuantity(batchProductionPlan.getProductionQuantity())
                        .shipmentTime(batchProductionPlan.getShipmentTime())
                        .status(ProductionPlan.Status.checkpending)
                        .orderId(batchProductionPlanAddForm.getOrderId())
                        .planSource(batchProductionPlanAddForm.getPlanSource())
                        .planClassifyId(batchProductionPlanAddForm.getPlanClassifyId())
                        .signOrNot(batchProductionPlanAddForm.getSignOrNot())
                        .contractId(batchProductionPlanAddForm.getContractId())
                        .planTypeId(batchProductionPlanAddForm.getPlanTypeId())
                        .planNature(batchProductionPlan.getPlanNature())
                        .processId(batchProductionPlan.getProcessId())
                        .demandQuantity(batchProductionPlan.getDemandQuantity())
                        .outputTime(batchProductionPlan.getOutputTime())
                        .packName(batchProductionPlan.getPackName())
                        .orderProId(batchProductionPlan.getOrderProId())
                        .bookId(batchProductionPlan.getBookId())
                        .productDetailId(batchProductionPlan.getProductDetailId())
                        .productNatureName(batchProductionPlan.getProductNatureName())
                        .workshopId(batchProductionPlan.getWorkshopId())
                        .build();
                plans.add(productionPlan);
                //2. 判断得出剩余计划量 （此操作目前仅限于 量产+正式 订单）
                //量产计划
                if (productionPlan.getOrderType().equals(ProductionPlan.OrderType.finish)) {
                    //查询订单排产的物料列表
                    List<OrderSkuDetailSearchVo> finishDetailBy = this.baseMapper.getFinishDetailBy(productionPlan.getOrderId());
                    if (CollectionUtil.isNotEmpty(finishDetailBy)) {
                        Map<String, Object> quantityByf = productionPlanService.getQuantityBy(productionPlan.getOrderId(), ProductionPlan.OrderType.finish.getDesc(), batchProductionPlan.getProductDetailId());
                        if (ObjectUtil.isNotEmpty(quantityByf)) {
                            //未排产数量
                            int noQuantityNum =  quantityByf.get("noQuantityNum") == null?0:(Integer)quantityByf.get("noQuantityNum");
                            if (noQuantityNum > 0 && noQuantityNum - productionPlan.getProductionQuantity()<=0) {
                                //排产完成
                                this.baseMapper.updateFinishedOrderPcStatusBy(productionPlan.getOrderId(), MaintenanceEnum.pcStatusEmum.PCWC.getCode());
                            }else{
                                this.baseMapper.updateFinishedOrderPcStatusBy(productionPlan.getOrderId(), MaintenanceEnum.pcStatusEmum.PCZ.getCode());
                            }
                        }
                    }
                }else if (productionPlan.getOrderType().equals(ProductionPlan.OrderType.order)){
                    //判断剩余排产数的数量
                    Map<String, Object> quantityBy = productionPlanService.getQuantityBy(productionPlan.getOrderId(), ProductionPlan.OrderType.order.getDesc(), batchProductionPlan.getProductDetailId());
                    if (ObjectUtil.isNotEmpty(quantityBy)) {
                        //未排产数量
                        int noQuantityNum =  quantityBy.get("noQuantityNum") == null?0:(Integer)quantityBy.get("noQuantityNum");
                        if (noQuantityNum > 0 && noQuantityNum - productionPlan.getProductionQuantity()<=0) {
                            this.baseMapper.updateOrderPcStatusBy(productionPlan.getOrderId(), MaintenanceEnum.pcStatusEmum.PCWC.getCode());
                        }else{
                            this.baseMapper.updateOrderPcStatusBy(productionPlan.getOrderId(), MaintenanceEnum.pcStatusEmum.PCZ.getCode());
                        }
                    }
                }
            }
            //直接保存排产记录
            boolean saved = this.saveBatch(plans);
            if (saved) {
                return 1;
            }
        }
        return 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int   add(ProductionPlanForm productionPlanForm) {

        //校验
        ProductionPlan productionPlan = new ProductionPlan();
        CopyOptions copyOptions = CopyOptions.create()
                .setEditable(ProductionPlan.class)
                .setIgnoreError(true)
                .setIgnoreNullValue(true);
        if (ObjectUtil.isNull(productionPlanForm.getOrderType())){
            productionPlanForm.setOrderType(ProductionPlan.OrderType.other);
        }
        BeanUtil.copyProperties(productionPlanForm, productionPlan, copyOptions);
        String today = DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN);
        Integer maxNo = dynamicDao.getDayMaxNo("ord_production_plan");
        String code = CodeUtil.getCode(maxNo);
        productionPlan.setNo(Integer.valueOf(code))
                .setDay(Integer.valueOf(today))
                .setCreator(JwtUtils.getLoginUserId())
                .setCreatorName(JwtUtils.getLoginUsername())
                .setPhone(JwtUtils.getPhone())
                .setCode("P" + today + code);
        int insert = baseMapper.insert(productionPlan);
        if (insert > 0) {
            //根据订单类型 判断 并修改订单的排产状态
            //量产计划
            if (productionPlanForm.getOrderType().equals(ProductionPlan.OrderType.finish)) {
                //查询订单排产的物料列表
                List<OrderSkuDetailSearchVo> finishDetailBy = this.baseMapper.getFinishDetailBy(productionPlanForm.getOrderId());
                if (CollectionUtil.isNotEmpty(finishDetailBy)) {
                    Map<String, Object> quantityByf = productionPlanService.getQuantityBy(productionPlanForm.getOrderId(), ProductionPlan.OrderType.finish.getDesc(), productionPlanForm.getProductDetailId());
                    if (ObjectUtil.isNotEmpty(quantityByf)) {
                        //未排产数量
                        int noQuantityNum =  quantityByf.get("noQuantityNum") == null?0:(Integer)quantityByf.get("noQuantityNum");
                        if (noQuantityNum > 0 && noQuantityNum - productionPlanForm.getProductionQuantity()<=0) {
                            //排产完成
                            this.baseMapper.updateFinishedOrderPcStatusBy(productionPlanForm.getOrderId(), MaintenanceEnum.pcStatusEmum.PCWC.getCode());
                            return 1;
                        }else{
                            this.baseMapper.updateFinishedOrderPcStatusBy(productionPlanForm.getOrderId(), MaintenanceEnum.pcStatusEmum.PCZ.getCode());
                            return 1;
                        }
                    }
                }
            }else if (productionPlanForm.getOrderType().equals(ProductionPlan.OrderType.order)){
                //判断剩余排产数的数量
                Map<String, Object> quantityBy = productionPlanService.getQuantityBy(productionPlanForm.getOrderId(), ProductionPlan.OrderType.order.getDesc(), productionPlanForm.getProductDetailId());
                if (ObjectUtil.isNotEmpty(quantityBy)) {
                    //未排产数量
                    int noQuantityNum =  quantityBy.get("noQuantityNum") == null?0:(Integer)quantityBy.get("noQuantityNum");
                    if (noQuantityNum > 0 && noQuantityNum - productionPlanForm.getProductionQuantity()<=0) {
                        this.baseMapper.updateOrderPcStatusBy(productionPlanForm.getOrderId(), MaintenanceEnum.pcStatusEmum.PCWC.getCode());
                        return 1;
                    }else{
                        this.baseMapper.updateOrderPcStatusBy(productionPlanForm.getOrderId(), MaintenanceEnum.pcStatusEmum.PCZ.getCode());
                        return 1;
                    }
                }
            }
        }
        return 1;
    }

}
